//#include "Matrix.h"
#include "FileIO.h"

#include <direct.h>
#include <io.h>
#include <iomanip>
#include <iostream>

CFileIO::CFileIO(void)
{
    _nSetFieldWidth = 12;

    char cBuffer[_MAX_PATH];
    string sCWDir;

    /* Get the current working directory: */
    if( _getcwd( cBuffer, _MAX_PATH ) == NULL )
        perror( "_getcwd error" );
    else
        sCWDir.assign(cBuffer);

    if (sCWDir[sCWDir.length()-1]!='\\')
        sCWDir += '\\';

    setCurrentWD() = sCWDir;

}

CFileIO::~CFileIO(void)
{
    CloseFile();
}

// common
void CFileIO::CloseFile()
{
	_File.close();
}

void CFileIO::GetFileSize(int* nFileSize_ )
{
	_File.seekg(0, ios::end);
	*nFileSize_ = (int)_File.tellg();
	_File.seekg(0, ios::beg); // reset file pointer to beginning of file
	return;
}

// reading
void CFileIO::OpenFileRead(const string& sFileName_)
{
	_File.open(sFileName_.c_str(), ios::in);
	if (!_File.is_open() | _File.fail())
	{
        string strText = "Unable to open file \"" + sFileName_ + "\" for reading.\n";
        throw exception(strText.c_str());
    }
    _File.precision(18);
    _nLinesRead = 0;
    return;
}

bool CFileIO::IsEOF() const
{
    return _File.eof();
}

bool CFileIO::ReadLine(string* pLine_)
{
	char aLine[256];
	bool bSuccess = false;

	while (IsEOF()==false)
	{
		_File.getline(aLine,256);
		pLine_->assign(aLine);
		_nLinesRead++;
		
		if (pLine_->length()==0) // empty line
			continue;

		if (pLine_->find("#")==0) // if pound sign is found on position 0 (first char of line), we've got a comment: skip this line
			continue;
		
		bSuccess = true; // we've read an interesting line
		break;  // found a valid line, break out
	}
	return bSuccess;
}

void CFileIO::ReadFile(string* pStr_)
{
	// get file size
	int nFileSize;
	GetFileSize(&nFileSize);

	// create buffer of right size, initialize to zero
	char* cFileContents;
	cFileContents = new char [nFileSize];
	memset(cFileContents,'\0',nFileSize);

	// read file
	_File.read(cFileContents,nFileSize);
	pStr_->assign(cFileContents);

	delete[] cFileContents;

	return;
}

// writing
void CFileIO::CreateCWDir(string& sDirName_)
{
	// get current working directory
	char cBuffer[_MAX_PATH];
	string sCWDir;

	/* Get the current working directory: */
	if( _getcwd( cBuffer, _MAX_PATH ) == NULL )
		perror( "_getcwd error" );
	else
		sCWDir.assign(cBuffer);

	if (sCWDir[sCWDir.length()-1]=='\\' || sDirName_[0]=='\\')
		sCWDir += sDirName_;
	else if(sCWDir[sCWDir.length()-1]=='\\' && sDirName_[0]=='\\')
	{
		sCWDir.erase(sCWDir.end());
		sCWDir += sDirName_;
	}
	else
		sCWDir = sCWDir + '\\' + sDirName_;

	setCurrentWD() = sCWDir;

	// check uniqueness of the directory to be created
	if (_access(sCWDir.c_str(),0)==0)
	{
		return;
	}

	// create
	if( _mkdir( sCWDir.c_str() ) != 0 )
	{
        string strText = "Directory \"" + sCWDir + "\" cannot be created.\n";
        throw exception(strText.c_str());
	}

	// check again
	if (_access(sCWDir.c_str(),0)==0)
	{
        string strText = "Directory \"" + sCWDir + "\" created successfully.\n" ;
	}

	return;
}
void CFileIO::OpenFileWrite(const string& sFileName_, bool bCheckFileExist_/*=false*/ )
{
	string sFullFileName;
	sFullFileName = currentWD() + '\\' + sFileName_; 

    if(bCheckFileExist_)
        CheckFileExist(sFileName_);
	// check if file exists

	_File.open(sFullFileName.c_str(), ios::out);
	if (!_File.is_open() | _File.fail())
	{
        string strText = "Unable to create file \"" + sFullFileName + "\" .";
        throw exception(strText.c_str());
	}
    _File.precision(20);
	return;
}

void CFileIO::CheckFileExist(const string& sFileName_)
{
    string sFullFileName;
    sFullFileName = currentWD() + '\\' + sFileName_; 
    // check if file exists
    if (_access(sFullFileName.c_str(),0)==0)
    {
        string strText = "File \"" + sFullFileName + "\" already exits.";
        throw exception(strText.c_str());
    }
}

/*
void CFileIO::WriteDoubleMatToFile(const CMatrix<double>& mMat_, const string& sHeader_)
{
    if (!sHeader_.empty())
	    _File << sHeader_.c_str() << endl;
	for (int r=0; r<mMat_.Rows(); r++)
	{
		for (int c=0; c<mMat_.Cols(); c++)
		{
			_File << mMat_(r,c) << "\t";
		}
		_File << endl;
	}
	_File << endl;

	// error checking (after every write actually)

	return;
}

void CFileIO::WriteIntMatToFile( const CMatrix<int>& mMat_, const string& sHeader_ )
{
	_File << sHeader_.c_str() << endl;
	for (int r=0; r<mMat_.Rows(); r++)
	{
		for (int c=0; c<mMat_.Cols(); c++)
		{
			_File << mMat_(r,c) << "\t";
		}
		_File << endl;
	}
	_File << endl;

	// error checking (after every write actually)

	return;
}
*/
void CFileIO::WriteDoubleVecToFile(const vector<double>& vVec_, const string& sHeader_)
{
	_File << sHeader_.c_str() << endl;
	for (unsigned int i=0; i<vVec_.size(); i++)
	{
		_File << vVec_[i] << endl;
	}
	_File << endl;

	// error checking (after every write actually)

	return;
}

void CFileIO::WriteUIntVecToFile( const vector<unsigned int>& vVec_, const string& sHeader_ )
{
	_File << sHeader_.c_str() << endl;
	for (unsigned int i=0; i<vVec_.size(); i++)
	{
		_File << vVec_[i] << endl;
	}
	_File << endl;

	// error checking (after every write actually)

	return;
}

void CFileIO::WriteIntValToFile(const int& nVal_, const string& sHeader_)
{
	_File << sHeader_.c_str() << endl;
	_File << nVal_ << endl << endl;

	// error checking

	return;
}


void CFileIO::WriteDoubleValToFile(const double& dVal_, const string& sHeader_)
{
    WriteStrValToFile(sHeader_);
    WriteEndl();
    WriteDblValToFile(dVal_);
    WriteEndl();
    WriteEndl();
	//_File << sHeader_.c_str() << endl;
	//_File << nVal_ << endl << endl;

	// error checking

	return;
}
void CFileIO::WriteIntValToFile( const int& nVal_ )
{
    _File << /*setw(_nSetFieldWidth)<<*/nVal_;
}
void CFileIO::WriteDblValToFile( const double& dVal_ )
{
    _File << /*setw(_nSetFieldWidth)<<*/ dVal_;
}
void CFileIO::WriteStrValToFile( const string& strVal_ )
{
    _File << /*setw(_nSetFieldWidth)<<*/ strVal_.c_str();
}

void CFileIO::WriteSpace()
{
    _File <<" ";
}
void CFileIO::WriteTab()
{
    _File <<"\t";
}

void CFileIO::WriteEndl()
{
    _File <<endl;
}

void CFileIO::DelFile(const string& sFileName_)
{
    CloseFile();
    string sFullFileName;
    sFullFileName = currentWD() + '\\' + sFileName_; 
    int nResult = std::remove(sFullFileName.c_str());
    return;
}